a11y: Add a display to GtkATContext
authorEmmanuele Bassi <ebassi@gnome.org>
Tue, 29 Sep 2020 17:40:44 +0000 (18:40 +0100)
committerEmmanuele Bassi <ebassi@gnome.org>
Mon, 12 Oct 2020 15:19:32 +0000 (16:19 +0100)
Since we need to check at run time what kind of AT context to use, we
need a hook into the whole GDK backend machinery. The display connection
seems to be the best choice, in this case, as it allows us to determine
whether we're running on an X11 or Wayland system, and thus whether we
should create a GtkAtSpiContext.

This requires some surgery to fix the GtkATContext creation function, in
order to include a GdkDisplay instance.

gtk/a11y/gtkatspicontext.c
gtk/a11y/gtkatspicontextprivate.h
gtk/gtkatcontext.c
gtk/gtkatcontext.h
gtk/gtkatcontextprivate.h
gtk/gtkwidget.c
testsuite/a11y/accessible.c

index 95fc3429173ac4e05aef29ef24e5d2f91a66011c..104458020b502da6f6cba2bc7b5070e79fe2c683 100644 (file)
 
 #include "gtkatspicontextprivate.h"
 
+#if defined(GDK_WINDOWING_WAYLAND)
+# include <gdk/wayland/gdkwaylanddisplay.h>
+#endif
+#if defined(GDK_WINDOWING_X11)
+# include <gdk/x11/gdkx11display.h>
+#endif
+
 struct _GtkAtSpiContext
 {
   GtkATContext parent_instance;
@@ -62,24 +69,30 @@ gtk_at_spi_context_init (GtkAtSpiContext *self)
 {
 }
 
-/*< private >
- * gtk_at_spi_context_new:
- * @accessible_role: the accessible role for the AT context
- * @accessible: the #GtkAccessible instance which owns the context
- *
- * Creates a new #GtkAtSpiContext instance for @accessible, using the
- * given @accessible_role.
- *
- * Returns: (transfer full): the newly created #GtkAtSpiContext
- */
 GtkATContext *
-gtk_at_spi_context_new (GtkAccessibleRole  accessible_role,
-                        GtkAccessible *    accessible)
+gtk_at_spi_create_context (GtkAccessibleRole  accessible_role,
+                           GtkAccessible     *accessible,
+                           GdkDisplay        *display)
 {
   g_return_val_if_fail (GTK_IS_ACCESSIBLE (accessible), NULL);
+  g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
+
+#if defined(GDK_WINDOWING_WAYLAND)
+  if (GDK_IS_WAYLAND_DISPLAY (display))
+    return g_object_new (GTK_TYPE_AT_SPI_CONTEXT,
+                         "accessible-role", accessible_role,
+                         "accessible", accessible,
+                         "display", display,
+                         NULL);
+#endif
+#if defined(GDK_WINDOWING_X11)
+  if (GDK_IS_X11_DISPLAY (display))
+    return g_object_new (GTK_TYPE_AT_SPI_CONTEXT,
+                         "accessible-role", accessible_role,
+                         "accessible", accessible,
+                         "display", display,
+                         NULL);
+#endif
 
-  return g_object_new (GTK_TYPE_AT_SPI_CONTEXT,
-                       "accessible-role", accessible_role,
-                       "accessible", accessible,
-                       NULL);
+  return NULL;
 }
index 28205f1fbcdd487a496ac15254db063444780fe5..d7457af0bab91d1aabd0f8464a87bca65eda0618 100644 (file)
@@ -29,7 +29,8 @@ G_BEGIN_DECLS
 G_DECLARE_FINAL_TYPE (GtkAtSpiContext, gtk_at_spi_context, GTK, AT_SPI_CONTEXT, GtkATContext)
 
 GtkATContext *
-gtk_at_spi_context_new (GtkAccessibleRole  accessible_role,
-                        GtkAccessible     *accessible);
+gtk_at_spi_create_context (GtkAccessibleRole  accessible_role,
+                           GtkAccessible     *accessible,
+                           GdkDisplay        *display);
 
 G_END_DECLS
index 4d86a2346d6d6190dc7cc6db3b576b21a9222864..9b586c26bbfd1d5c98d49e7105e1fa7eb2525de7 100644 (file)
@@ -50,6 +50,7 @@ enum
 {
   PROP_ACCESSIBLE_ROLE = 1,
   PROP_ACCESSIBLE,
+  PROP_DISPLAY,
 
   N_PROPS
 };
@@ -95,6 +96,10 @@ gtk_at_context_set_property (GObject      *gobject,
       self->accessible = g_value_get_object (value);
       break;
 
+    case PROP_DISPLAY:
+      self->display = g_value_get_object (value);
+      break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
     }
@@ -118,6 +123,10 @@ gtk_at_context_get_property (GObject    *gobject,
       g_value_set_object (value, self->accessible);
       break;
 
+    case PROP_DISPLAY:
+      g_value_set_object (value, self->display);
+      break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
     }
@@ -177,6 +186,20 @@ gtk_at_context_class_init (GtkATContextClass *klass)
                          G_PARAM_CONSTRUCT_ONLY |
                          G_PARAM_STATIC_STRINGS);
 
+  /**
+   * GtkATContext:display:
+   *
+   * The #GdkDisplay for the #GtkATContext.
+   */
+  obj_props[PROP_DISPLAY] =
+    g_param_spec_object ("display",
+                         "Display",
+                         "The display connection",
+                         GDK_TYPE_DISPLAY,
+                         G_PARAM_READWRITE |
+                         G_PARAM_CONSTRUCT_ONLY |
+                         G_PARAM_STATIC_STRINGS);
+
   /**
    * GtkATContext::state-change:
    * @self: the #GtkATContext
@@ -359,16 +382,33 @@ gtk_at_context_get_accessible_role (GtkATContext *self)
   return self->accessible_role;
 }
 
+/*< private >
+ * gtk_at_context_get_display:
+ * @self: a #GtkATContext
+ *
+ * Retrieves the #GdkDisplay used to create the context.
+ *
+ * Returns: (transfer none): a #GdkDisplay
+ */
+GdkDisplay *
+gtk_at_context_get_display (GtkATContext *self)
+{
+  g_return_val_if_fail (GTK_IS_AT_CONTEXT (self), NULL);
+
+  return self->display;
+}
+
 static const struct {
   const char *name;
   GtkATContext * (* create_context) (GtkAccessibleRole accessible_role,
-                                     GtkAccessible    *accessible);
+                                     GtkAccessible    *accessible,
+                                     GdkDisplay       *display);
 } a11y_backends[] = {
 #if defined(GDK_WINDOWING_WAYLAND)
-  { "AT-SPI", _gtk_at_spi_context_new },
+  { "AT-SPI (Wayland)", gtk_at_spi_create_context },
 #endif
 #if defined(GDK_WINDOWING_X11)
-  { "AT-SPI", gtk_at_spi_context_new },
+  { "AT-SPI (X11)", gtk_at_spi_create_context },
 #endif
   { NULL, NULL },
 };
@@ -377,9 +417,10 @@ static const struct {
  * gtk_at_context_create: (constructor)
  * @accessible_role: the accessible role used by the #GtkATContext
  * @accessible: the #GtkAccessible implementation using the #GtkATContext
+ * @display: the #GdkDisplay used by the #GtkATContext
  *
- * Creates a new #GtkATContext instance for the given accessible role and
- * accessible instance.
+ * Creates a new #GtkATContext instance for the given accessible role,
+ * accessible instance, and display connection.
  *
  * The #GtkATContext implementation being instantiated will depend on the
  * platform.
@@ -388,7 +429,8 @@ static const struct {
  */
 GtkATContext *
 gtk_at_context_create (GtkAccessibleRole  accessible_role,
-                       GtkAccessible     *accessible)
+                       GtkAccessible     *accessible,
+                       GdkDisplay        *display)
 {
   static const char *gtk_test_accessible;
   static const char *gtk_no_a11y;
@@ -424,16 +466,25 @@ gtk_at_context_create (GtkAccessibleRole  accessible_role,
 
   for (guint i = 0; i < G_N_ELEMENTS (a11y_backends); i++)
     {
+      if (a11y_backends[i].name == NULL)
+        break;
+
       GTK_NOTE (A11Y, g_message ("Trying %s a11y backend", a11y_backends[i].name));
       if (a11y_backends[i].create_context != NULL)
         {
-          res = a11y_backends[i].create_context (accessible_role, accessible);
-          break;
+          res = a11y_backends[i].create_context (accessible_role, accessible, display);
+          if (res != NULL)
+            break;
         }
     }
 
+  /* Fall back to the test context, so we can get debugging data */
   if (res == NULL)
-    res = gtk_test_at_context_new (accessible_role, accessible);
+    res = g_object_new (GTK_TYPE_TEST_AT_CONTEXT,
+                        "accessible_role", accessible_role,
+                        "accessible", accessible,
+                        "display", display,
+                        NULL);
 
   /* FIXME: Add GIOExtension for AT contexts */
   return res;
index e6b742ffb0cc1be9d899fb9fc2fe6da2f27a304a..2372f04b94d59172b0d92799c4d777748a19b981 100644 (file)
@@ -42,6 +42,7 @@ GtkAccessibleRole       gtk_at_context_get_accessible_role      (GtkATContext
 
 GDK_AVAILABLE_IN_ALL
 GtkATContext *          gtk_at_context_create                   (GtkAccessibleRole  accessible_role,
-                                                                 GtkAccessible     *accessible);
+                                                                 GtkAccessible     *accessible,
+                                                                 GdkDisplay        *display);
 
 G_END_DECLS
index 2b916187fdc8a1614370df52c24ef7ffbb685478..115a057cb7b832589723c5f4b762ca372c5c5949 100644 (file)
@@ -86,6 +86,7 @@ struct _GtkATContext
 
   GtkAccessibleRole accessible_role;
   GtkAccessible *accessible;
+  GdkDisplay *display;
 
   GtkAccessibleAttributeSet *states;
   GtkAccessibleAttributeSet *properties;
@@ -109,6 +110,8 @@ struct _GtkATContextClass
                          GtkAccessibleAttributeSet   *relations);
 };
 
+GdkDisplay *            gtk_at_context_get_display              (GtkATContext          *self);
+
 void                    gtk_at_context_update                   (GtkATContext          *self);
 
 void                    gtk_at_context_set_accessible_state     (GtkATContext          *self,
index 2ea7fb9c3ae205051a0f55aec9f18c83b52b7a19..b6489a284a93ea94a836c9ecd9f4064602f00fec 100644 (file)
@@ -8095,6 +8095,7 @@ gtk_widget_accessible_get_at_context (GtkAccessible *accessible)
     {
       GtkWidgetClass *widget_class = GTK_WIDGET_GET_CLASS (self);
       GtkWidgetClassPrivate *class_priv = widget_class->priv;
+      GdkDisplay *display = _gtk_widget_get_display (self);
       GtkAccessibleRole role;
 
       /* Widgets have two options to set the accessible role: either they
@@ -8111,7 +8112,7 @@ gtk_widget_accessible_get_at_context (GtkAccessible *accessible)
         role = class_priv->accessible_role;
 
       priv->accessible_role = role;
-      priv->at_context = gtk_at_context_create (role, accessible);
+      priv->at_context = gtk_at_context_create (role, accessible, display);
     }
 
   return priv->at_context;
index b8daf9e1823f7995524c604b7fba0b19c73086e5..b353d9e94e4ced2d762b3d23e9cf4fc921736f73 100644 (file)
@@ -29,7 +29,9 @@ test_object_accessible_get_at_context (GtkAccessible *accessible)
   TestObject *self = (TestObject*)accessible;
 
   if (self->at_context == NULL)
-    self->at_context = gtk_at_context_create (self->role, accessible);
+    self->at_context = gtk_at_context_create (self->role,
+                                              accessible,
+                                              gdk_display_get_default ());
 
   return self->at_context;
 }